package slu.appli.sound.impl;

import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.IOException;

import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.SourceDataLine;
import javax.sound.sampled.UnsupportedAudioFileException;

import slu.appli.logger.interfaces.LoggerInterface;
import slu.appli.sound.interfaces.SoundPlayerInterface;
public class Sound
implements SoundPlayerInterface {
	
	private AudioFormat format;
	private LoggerInterface logger;
	private byte[] datas; 
	
	public Sound() {
		super();
	}
	
	public Sound(String ressourceName, LoggerInterface logger){
		this.setLogger(logger);
		this.setFile(ressourceName);
	}
	
	public LoggerInterface getLogger() {
		return logger;
	}

	@Override
	public void setLogger(LoggerInterface logger) {
		this.logger = logger;
	}

	@Override
	public void setFile(String ressourceName) {
		try{
			AudioInputStream stream = 
				AudioSystem.getAudioInputStream(Sound.class.getClassLoader().getResourceAsStream(ressourceName));
			this.format = stream.getFormat();
			this.datas = this.getSamples(stream);
		}
		catch (UnsupportedAudioFileException e){
			this.logger.addException(e);
		}
		catch (IOException e){
			this.logger.addException(e);
		}
	}
	
	private byte[] getSamples(AudioInputStream stream){
		int length = (int)(stream.getFrameLength() * this.format.getFrameSize());
		byte[] samples = new byte[length];
		DataInputStream in = new DataInputStream(stream);
		try{
			in.readFully(samples);
		}
		catch (IOException e){
			this.logger.addException(e);
		}
		return samples;
	}

	@Override
	public void play() {
		// 100 ms buffer for real time change to the sound stream
		int bufferSize = this.format.getFrameSize() * Math.round(this.format.getSampleRate() / 10);
		byte[] buffer = new byte[bufferSize];
		SourceDataLine line = null;
		try{
			DataLine.Info info = new DataLine.Info(SourceDataLine.class, this.format);
			line = (SourceDataLine)AudioSystem.getLine(info);
			line.open(this.format, bufferSize);
			line.start();
			int numBytesRead = 0;
			ByteArrayInputStream stream = new ByteArrayInputStream(this.datas);
			while (numBytesRead != -1){
				numBytesRead = stream.read(buffer, 0, buffer.length);
				if (numBytesRead != -1)
					line.write(buffer, 0, numBytesRead);
			}
		}
		catch (Exception e){
			this.logger.addException(e);
		} finally {
			if (line != null) {
				line.drain();
				line.close();
			}
		}
	}

	public void close() {
		
	}
}
